package com.hfengxiang.example.canvasrotatedemo;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

public class RotateViewV1 extends View implements RotateProcessor.OnRotateListener {

    private Paint paint;
    private Bitmap bitmap;
    private int rotation = 0;
    private float currentScale = 1f;
    private RectF rectF;
    private RotateProcessor rotateProcessor;
    private boolean isRecover;
    private PointF translate = new PointF(0, 0);
    private PointF rotateCenter;
    private PointF recoverCenter;
    private RotateInfo mInfo;
    private Matrix matrix;
    private int coordinatorX = 100;
    private int coordinatorY = 200;

    public RotateViewV1 setTranslate(float x, float y) {
        translate.set(x, y);
        return this;
    }

    public RotateViewV1(Context context) {
        this(context, null);
    }

    public RotateViewV1(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public RotateViewV1(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        paint = new Paint();
        paint.setAntiAlias(true);
        bitmap = Utils.getPhoto(getResources(), getResources().getDisplayMetrics().widthPixels);
        rectF = new RectF();
        rotateCenter = new PointF();
        recoverCenter = new PointF();
        rotateCenter.set(0f, 0f);
        rotateProcessor = new RotateProcessor();
        rotateProcessor.setRotateListener(this);
        matrix = new Matrix();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        currentScale = ScaleCalculator.calculateScale(getWidth(), getHeight(), bitmap.getWidth(), bitmap.getHeight(), 0);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        Utils.drawAxis(canvas, currentWidth() * 2, currentHeight() * 2, "canvas初始坐标系");
        canvas.translate(getWidth() / 2f, getHeight() / 2f);
        Utils.drawAxis(canvas, currentWidth() * 2f, currentHeight() * 2f, "canvas平移至屏幕中央坐标系");
        canvas.save();
        // 假设这里准确计算出了屏幕中心点（100,200）
        canvas.rotate(rotation, rotateCenter.x, rotateCenter.y);
        // 旋转中心不变，只要不是原点，依然会飘
//        canvas.rotate(rotation, coordinatorX, coordinatorY);

        rectF.set(-currentWidth() / 2f, -currentHeight() / 2f,
                currentWidth() / 2f, currentHeight() / 2f);
        canvas.drawBitmap(bitmap, null, rectF, paint);
        // canvas旋转后的坐标系
        drawMarkerAfterCanvasRotate(canvas);
        Utils.drawAxis(canvas, currentWidth(), currentHeight(), "canvas旋转后的坐标系");
        canvas.restore();
        // canvas旋转前的坐标系
        drawMarkerBeforeCanvasRotate(canvas);
        canvas.restore();
    }

    private void drawMarkerBeforeCanvasRotate(Canvas canvas) {
        paint.setColor(Color.RED);
        canvas.drawCircle(0, 0, 5, paint);
        paint.setColor(Color.YELLOW);
        coordinatorX = 100;
        Utils.drawCoordinate(canvas, coordinatorX, coordinatorY, true);
        Utils.drawCoordinate(canvas, coordinatorY, -coordinatorX, true);
        Utils.drawCoordinate(canvas, -coordinatorX, -coordinatorY, true);
        Utils.drawCoordinate(canvas, -coordinatorY, coordinatorX, true);
    }

    private void drawMarkerAfterCanvasRotate(Canvas canvas) {
        paint.setColor(Color.BLUE);
        canvas.drawCircle(0, 0, 5, paint);
        paint.setColor(Color.GREEN);
        Utils.drawCoordinate(canvas, coordinatorX, coordinatorY, false);
        Utils.drawCoordinate(canvas, coordinatorY, -coordinatorX, false);
        Utils.drawCoordinate(canvas, -coordinatorX, -coordinatorY, false);
        Utils.drawCoordinate(canvas, -coordinatorY, coordinatorX, false);
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_POINTER_DOWN:
                rotateProcessor.handleActionDown(event);
                break;
            case MotionEvent.ACTION_MOVE:
                rotateProcessor.handleActionMove(event);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                rotateProcessor.handleActionUp(event);
                break;
        }
        return true;
    }

    private float currentWidth() {
        return bitmap.getWidth() * currentScale;
    }

    private float currentHeight() {
        return bitmap.getHeight() * currentScale;
    }

    @Override
    public void onRotate(RotateInfo info) {
        mInfo = info;
        rotation = (int) info.getTotalDegree();
        if (info.isRecovering()) {
            // 为了方便观察先不改变缩放值
            currentScale = info.getScale();
            rotateCenter.set(recoverCenter.x * (1 - info.getProgress()),
                    recoverCenter.y * (1 - info.getProgress()));
        }
        invalidate();
    }

    @Override
    public void onRotateStart(RotateInfo info) {
        float totalDegree = info.getTotalDegree();
        float degree = totalDegree % 360;
        if (degree < 0) {
            degree = 360 + degree;
        }
        int level = calculateLevel(degree);
        rotateCenter.set(100, 200);
        Log.i("onRotateStart", "degree=" + degree);
        Log.i("onRotateStart", "level=" + level);
        recoverCenter.set(rotateCenter);
//        switch (level) {
//            case 0:
//                rotateCenter.set(coordinatorX, coordinatorY);
//                break;
//            case 1:
//                rotateCenter.set(coordinatorY, -coordinatorX);
//                break;
//            case 2:
//                rotateCenter.set(-coordinatorX, -coordinatorY);
//                break;
//            case 3:
//                rotateCenter.set(-coordinatorY, coordinatorX);
//                break;
//        }
//        translate.set(-rotateCenter.x, -rotateCenter.y);
        Log.i("onRotateStart", "rotateCenter.x=" + rotateCenter.x);
        Log.i("onRotateStart", "rotateCenter.y=" + rotateCenter.y);

    }

    @Override
    public void onRecoverStart(RotateInfo info) {

    }

    @Override
    public void onRotateEnd(RotateInfo rotateInfo) {
    }

    private int calculateLevel(float totalDegree) {
        float degree = totalDegree % 360;
        if (degree < 0) {
            degree = degree + 360;
        }
        return (int) (degree / 90);
    }

    @Override
    public float[] onCalculateScale(float targetDegree) {
        targetDegree = computeTargetDegree(targetDegree);
        Log.i("onCalculateScale", "targetScale=" + targetDegree);
        float targetScale = ScaleCalculator.calculateScale(getWidth(), getHeight(), bitmap.getWidth(), bitmap.getHeight(),
                (int) targetDegree);
        isRecover = true;
        return new float[]{currentScale, targetScale};
    }

    /**
     * 根据旋转的角度计算出图片复位应当到达的角度
     *
     * @param degree 旋转的角度
     * @return 目标角度
     */
    private int computeTargetDegree(double degree) {
        int[] degrees = {0, 90, 90, 180, 180, 270, 270, 360};
        degree = degree % 360;
        int index = (int) (degree / 45);
        if (index > 0) {
            return degrees[index];
        } else {
            return -1 * degrees[-1 * index];
        }
    }
}
